home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / DB / sqlite.php < prev    next >
Encoding:
PHP Script  |  2005-07-07  |  29.1 KB  |  943 lines

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * The PEAR DB driver for PHP's sqlite extension
  7.  * for interacting with SQLite databases
  8.  *
  9.  * PHP versions 4 and 5
  10.  *
  11.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  12.  * that is available through the world-wide-web at the following URI:
  13.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  14.  * the PHP License and are unable to obtain it through the web, please
  15.  * send a note to license@php.net so we can mail you a copy immediately.
  16.  *
  17.  * @category   Database
  18.  * @package    DB
  19.  * @author     Urs Gehrig <urs@circle.ch>
  20.  * @author     Mika Tuupola <tuupola@appelsiini.net>
  21.  * @author     Daniel Convissor <danielc@php.net>
  22.  * @copyright  1997-2005 The PHP Group
  23.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 3.0
  24.  * @version    CVS: $Id: sqlite.php,v 1.109 2005/03/10 01:22:48 danielc Exp $
  25.  * @link       http://pear.php.net/package/DB
  26.  */
  27.  
  28. /**
  29.  * Obtain the DB_common class so it can be extended from
  30.  */
  31. require_once 'DB/common.php';
  32.  
  33. /**
  34.  * The methods PEAR DB uses to interact with PHP's sqlite extension
  35.  * for interacting with SQLite databases
  36.  *
  37.  * These methods overload the ones declared in DB_common.
  38.  *
  39.  * NOTICE:  This driver needs PHP's track_errors ini setting to be on.
  40.  * It is automatically turned on when connecting to the database.
  41.  * Make sure your scripts don't turn it off.
  42.  *
  43.  * @category   Database
  44.  * @package    DB
  45.  * @author     Urs Gehrig <urs@circle.ch>
  46.  * @author     Mika Tuupola <tuupola@appelsiini.net>
  47.  * @author     Daniel Convissor <danielc@php.net>
  48.  * @copyright  1997-2005 The PHP Group
  49.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 3.0
  50.  * @version    Release: 1.7.6
  51.  * @link       http://pear.php.net/package/DB
  52.  */
  53. class DB_sqlite extends DB_common
  54. {
  55.     // {{{ properties
  56.  
  57.     /**
  58.      * The DB driver type (mysql, oci8, odbc, etc.)
  59.      * @var string
  60.      */
  61.     var $phptype = 'sqlite';
  62.  
  63.     /**
  64.      * The database syntax variant to be used (db2, access, etc.), if any
  65.      * @var string
  66.      */
  67.     var $dbsyntax = 'sqlite';
  68.  
  69.     /**
  70.      * The capabilities of this DB implementation
  71.      *
  72.      * The 'new_link' element contains the PHP version that first provided
  73.      * new_link support for this DBMS.  Contains false if it's unsupported.
  74.      *
  75.      * Meaning of the 'limit' element:
  76.      *   + 'emulate' = emulate with fetch row by number
  77.      *   + 'alter'   = alter the query
  78.      *   + false     = skip rows
  79.      *
  80.      * @var array
  81.      */
  82.     var $features = array(
  83.         'limit'         => 'alter',
  84.         'new_link'      => false,
  85.         'numrows'       => true,
  86.         'pconnect'      => true,
  87.         'prepare'       => false,
  88.         'ssl'           => false,
  89.         'transactions'  => false,
  90.     );
  91.  
  92.     /**
  93.      * A mapping of native error codes to DB error codes
  94.      *
  95.      * {@internal  Error codes according to sqlite_exec.  See the online
  96.      * manual at http://sqlite.org/c_interface.html for info.
  97.      * This error handling based on sqlite_exec is not yet implemented.}}
  98.      *
  99.      * @var array
  100.      */
  101.     var $errorcode_map = array(
  102.     );
  103.  
  104.     /**
  105.      * The raw database connection created by PHP
  106.      * @var resource
  107.      */
  108.     var $connection;
  109.  
  110.     /**
  111.      * The DSN information for connecting to a database
  112.      * @var array
  113.      */
  114.     var $dsn = array();
  115.  
  116.  
  117.     /**
  118.      * SQLite data types
  119.      *
  120.      * @link http://www.sqlite.org/datatypes.html
  121.      *
  122.      * @var array
  123.      */
  124.     var $keywords = array (
  125.         'BLOB'      => '',
  126.         'BOOLEAN'   => '',
  127.         'CHARACTER' => '',
  128.         'CLOB'      => '',
  129.         'FLOAT'     => '',
  130.         'INTEGER'   => '',
  131.         'KEY'       => '',
  132.         'NATIONAL'  => '',
  133.         'NUMERIC'   => '',
  134.         'NVARCHAR'  => '',
  135.         'PRIMARY'   => '',
  136.         'TEXT'      => '',
  137.         'TIMESTAMP' => '',
  138.         'UNIQUE'    => '',
  139.         'VARCHAR'   => '',
  140.         'VARYING'   => '',
  141.     );
  142.  
  143.     /**
  144.      * The most recent error message from $php_errormsg
  145.      * @var string
  146.      * @access private
  147.      */
  148.     var $_lasterror = '';
  149.  
  150.  
  151.     // }}}
  152.     // {{{ constructor
  153.  
  154.     /**
  155.      * This constructor calls <kbd>$this->DB_common()</kbd>
  156.      *
  157.      * @return void
  158.      */
  159.     function DB_sqlite()
  160.     {
  161.         $this->DB_common();
  162.     }
  163.  
  164.     // }}}
  165.     // {{{ connect()
  166.  
  167.     /**
  168.      * Connect to the database server, log in and open the database
  169.      *
  170.      * Don't call this method directly.  Use DB::connect() instead.
  171.      *
  172.      * PEAR DB's sqlite driver supports the following extra DSN options:
  173.      *   + mode  The permissions for the database file, in four digit
  174.      *            chmod octal format (eg "0600").
  175.      *
  176.      * Example of connecting to a database in read-only mode:
  177.      * <code>
  178.      * require_once 'DB.php';
  179.      * 
  180.      * $dsn = 'sqlite:///path/and/name/of/db/file?mode=0400';
  181.      * $options = array(
  182.      *     'portability' => DB_PORTABILITY_ALL,
  183.      * );
  184.      * 
  185.      * $db =& DB::connect($dsn, $options);
  186.      * if (PEAR::isError($db)) {
  187.      *     die($db->getMessage());
  188.      * }
  189.      * </code>
  190.      *
  191.      * @param array $dsn         the data source name
  192.      * @param bool  $persistent  should the connection be persistent?
  193.      *
  194.      * @return int  DB_OK on success. A DB_Error object on failure.
  195.      */
  196.     function connect($dsn, $persistent = false)
  197.     {
  198.         if (!PEAR::loadExtension('sqlite')) {
  199.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  200.         }
  201.  
  202.         $this->dsn = $dsn;
  203.         if ($dsn['dbsyntax']) {
  204.             $this->dbsyntax = $dsn['dbsyntax'];
  205.         }
  206.  
  207.         if ($dsn['database']) {
  208.             if (!file_exists($dsn['database'])) {
  209.                 if (!touch($dsn['database'])) {
  210.                     return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
  211.                 }
  212.                 if (!isset($dsn['mode']) ||
  213.                     !is_numeric($dsn['mode']))
  214.                 {
  215.                     $mode = 0644;
  216.                 } else {
  217.                     $mode = octdec($dsn['mode']);
  218.                 }
  219.                 if (!chmod($dsn['database'], $mode)) {
  220.                     return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
  221.                 }
  222.                 if (!file_exists($dsn['database'])) {
  223.                     return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
  224.                 }
  225.             }
  226.             if (!is_file($dsn['database'])) {
  227.                 return $this->sqliteRaiseError(DB_ERROR_INVALID);
  228.             }
  229.             if (!is_readable($dsn['database'])) {
  230.                 return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION);
  231.             }
  232.         } else {
  233.             return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION);
  234.         }
  235.  
  236.         $connect_function = $persistent ? 'sqlite_popen' : 'sqlite_open';
  237.  
  238.         // track_errors must remain on for simpleQuery()
  239.         ini_set('track_errors', 1);
  240.         $php_errormsg = '';
  241.  
  242.         if (!$this->connection = @$connect_function($dsn['database'])) {
  243.             return $this->raiseError(DB_ERROR_NODBSELECTED,
  244.                                      null, null, null,
  245.                                      $php_errormsg);
  246.         }
  247.         return DB_OK;
  248.     }
  249.  
  250.     // }}}
  251.     // {{{ disconnect()
  252.  
  253.     /**
  254.      * Disconnects from the database server
  255.      *
  256.      * @return bool  TRUE on success, FALSE on failure
  257.      */
  258.     function disconnect()
  259.     {
  260.         $ret = @sqlite_close($this->connection);
  261.         $this->connection = null;
  262.         return $ret;
  263.     }
  264.  
  265.     // }}}
  266.     // {{{ simpleQuery()
  267.  
  268.     /**
  269.      * Sends a query to the database server
  270.      *
  271.      * NOTICE:  This method needs PHP's track_errors ini setting to be on.
  272.      * It is automatically turned on when connecting to the database.
  273.      * Make sure your scripts don't turn it off.
  274.      *
  275.      * @param string  the SQL query string
  276.      *
  277.      * @return mixed  + a PHP result resrouce for successful SELECT queries
  278.      *                + the DB_OK constant for other successful queries
  279.      *                + a DB_Error object on failure
  280.      */
  281.     function simpleQuery($query)
  282.     {
  283.         $ismanip = DB::isManip($query);
  284.         $this->last_query = $query;
  285.         $query = $this->modifyQuery($query);
  286.  
  287.         $php_errormsg = '';
  288.  
  289.         $result = @sqlite_query($query, $this->connection);
  290.         $this->_lasterror = $php_errormsg ? $php_errormsg : '';
  291.  
  292.         $this->result = $result;
  293.         if (!$this->result) {
  294.             return $this->sqliteRaiseError(null);
  295.         }
  296.  
  297.         // sqlite_query() seems to allways return a resource
  298.         // so cant use that. Using $ismanip instead
  299.         if (!$ismanip) {
  300.             $numRows = $this->numRows($result);
  301.             if (is_object($numRows)) {
  302.                 // we've got PEAR_Error
  303.                 return $numRows;
  304.             }
  305.             return $result;
  306.         }
  307.         return DB_OK;
  308.     }
  309.  
  310.     // }}}
  311.     // {{{ nextResult()
  312.  
  313.     /**
  314.      * Move the internal sqlite result pointer to the next available result
  315.      *
  316.      * @param resource $result  the valid sqlite result resource
  317.      *
  318.      * @return bool  true if a result is available otherwise return false
  319.      */
  320.     function nextResult($result)
  321.     {
  322.         return false;
  323.     }
  324.  
  325.     // }}}
  326.     // {{{ fetchInto()
  327.  
  328.     /**
  329.      * Places a row from the result set into the given array
  330.      *
  331.      * Formating of the array and the data therein are configurable.
  332.      * See DB_result::fetchInto() for more information.
  333.      *
  334.      * This method is not meant to be called directly.  Use
  335.      * DB_result::fetchInto() instead.  It can't be declared "protected"
  336.      * because DB_result is a separate object.
  337.      *
  338.      * @param resource $result    the query result resource
  339.      * @param array    $arr       the referenced array to put the data in
  340.      * @param int      $fetchmode how the resulting array should be indexed
  341.      * @param int      $rownum    the row number to fetch (0 = first row)
  342.      *
  343.      * @return mixed  DB_OK on success, NULL when the end of a result set is
  344.      *                 reached or on failure
  345.      *
  346.      * @see DB_result::fetchInto()
  347.      */
  348.     function fetchInto($result, &$arr, $fetchmode, $rownum = null)
  349.     {
  350.         if ($rownum !== null) {
  351.             if (!@sqlite_seek($this->result, $rownum)) {
  352.                 return null;
  353.             }
  354.         }
  355.         if ($fetchmode & DB_FETCHMODE_ASSOC) {
  356.             $arr = @sqlite_fetch_array($result, SQLITE_ASSOC);
  357.             if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
  358.                 $arr = array_change_key_case($arr, CASE_LOWER);
  359.             }
  360.         } else {
  361.             $arr = @sqlite_fetch_array($result, SQLITE_NUM);
  362.         }
  363.         if (!$arr) {
  364.             return null;
  365.         }
  366.         if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  367.             /*
  368.              * Even though this DBMS already trims output, we do this because
  369.              * a field might have intentional whitespace at the end that
  370.              * gets removed by DB_PORTABILITY_RTRIM under another driver.
  371.              */
  372.             $this->_rtrimArrayValues($arr);
  373.         }
  374.         if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  375.             $this->_convertNullArrayValuesToEmpty($arr);
  376.         }
  377.         return DB_OK;
  378.     }
  379.  
  380.     // }}}
  381.     // {{{ freeResult()
  382.  
  383.     /**
  384.      * Deletes the result set and frees the memory occupied by the result set
  385.      *
  386.      * This method is not meant to be called directly.  Use
  387.      * DB_result::free() instead.  It can't be declared "protected"
  388.      * because DB_result is a separate object.
  389.      *
  390.      * @param resource $result  PHP's query result resource
  391.      *
  392.      * @return bool  TRUE on success, FALSE if $result is invalid
  393.      *
  394.      * @see DB_result::free()
  395.      */
  396.     function freeResult(&$result)
  397.     {
  398.         // XXX No native free?
  399.         if (!is_resource($result)) {
  400.             return false;
  401.         }
  402.         $result = null;
  403.         return true;
  404.     }
  405.  
  406.     // }}}
  407.     // {{{ numCols()
  408.  
  409.     /**
  410.      * Gets the number of columns in a result set
  411.      *
  412.      * This method is not meant to be called directly.  Use
  413.      * DB_result::numCols() instead.  It can't be declared "protected"
  414.      * because DB_result is a separate object.
  415.      *
  416.      * @param resource $result  PHP's query result resource
  417.      *
  418.      * @return int  the number of columns.  A DB_Error object on failure.
  419.      *
  420.      * @see DB_result::numCols()
  421.      */
  422.     function numCols($result)
  423.     {
  424.         $cols = @sqlite_num_fields($result);
  425.         if (!$cols) {
  426.             return $this->sqliteRaiseError();
  427.         }
  428.         return $cols;
  429.     }
  430.  
  431.     // }}}
  432.     // {{{ numRows()
  433.  
  434.     /**
  435.      * Gets the number of rows in a result set
  436.      *
  437.      * This method is not meant to be called directly.  Use
  438.      * DB_result::numRows() instead.  It can't be declared "protected"
  439.      * because DB_result is a separate object.
  440.      *
  441.      * @param resource $result  PHP's query result resource
  442.      *
  443.      * @return int  the number of rows.  A DB_Error object on failure.
  444.      *
  445.      * @see DB_result::numRows()
  446.      */
  447.     function numRows($result)
  448.     {
  449.         $rows = @sqlite_num_rows($result);
  450.         if ($rows === null) {
  451.             return $this->sqliteRaiseError();
  452.         }
  453.         return $rows;
  454.     }
  455.  
  456.     // }}}
  457.     // {{{ affected()
  458.  
  459.     /**
  460.      * Determines the number of rows affected by a data maniuplation query
  461.      *
  462.      * 0 is returned for queries that don't manipulate data.
  463.      *
  464.      * @return int  the number of rows.  A DB_Error object on failure.
  465.      */
  466.     function affectedRows()
  467.     {
  468.         return @sqlite_changes($this->connection);
  469.     }
  470.  
  471.     // }}}
  472.     // {{{ dropSequence()
  473.  
  474.     /**
  475.      * Deletes a sequence
  476.      *
  477.      * @param string $seq_name  name of the sequence to be deleted
  478.      *
  479.      * @return int  DB_OK on success.  A DB_Error object on failure.
  480.      *
  481.      * @see DB_common::dropSequence(), DB_common::getSequenceName(),
  482.      *      DB_sqlite::nextID(), DB_sqlite::createSequence()
  483.      */
  484.     function dropSequence($seq_name)
  485.     {
  486.         return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
  487.     }
  488.  
  489.     /**
  490.      * Creates a new sequence
  491.      *
  492.      * @param string $seq_name  name of the new sequence
  493.      *
  494.      * @return int  DB_OK on success.  A DB_Error object on failure.
  495.      *
  496.      * @see DB_common::createSequence(), DB_common::getSequenceName(),
  497.      *      DB_sqlite::nextID(), DB_sqlite::dropSequence()
  498.      */
  499.     function createSequence($seq_name)
  500.     {
  501.         $seqname = $this->getSequenceName($seq_name);
  502.         $query   = 'CREATE TABLE ' . $seqname .
  503.                    ' (id INTEGER UNSIGNED PRIMARY KEY) ';
  504.         $result  = $this->query($query);
  505.         if (DB::isError($result)) {
  506.             return($result);
  507.         }
  508.         $query   = "CREATE TRIGGER ${seqname}_cleanup AFTER INSERT ON $seqname
  509.                     BEGIN
  510.                         DELETE FROM $seqname WHERE id<LAST_INSERT_ROWID();
  511.                     END ";
  512.         $result  = $this->query($query);
  513.         if (DB::isError($result)) {
  514.             return($result);
  515.         }
  516.     }
  517.  
  518.     // }}}
  519.     // {{{ nextId()
  520.  
  521.     /**
  522.      * Returns the next free id in a sequence
  523.      *
  524.      * @param string  $seq_name  name of the sequence
  525.      * @param boolean $ondemand  when true, the seqence is automatically
  526.      *                            created if it does not exist
  527.      *
  528.      * @return int  the next id number in the sequence.
  529.      *               A DB_Error object on failure.
  530.      *
  531.      * @see DB_common::nextID(), DB_common::getSequenceName(),
  532.      *      DB_sqlite::createSequence(), DB_sqlite::dropSequence()
  533.      */
  534.     function nextId($seq_name, $ondemand = true)
  535.     {
  536.         $seqname = $this->getSequenceName($seq_name);
  537.  
  538.         do {
  539.             $repeat = 0;
  540.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  541.             $result = $this->query("INSERT INTO $seqname (id) VALUES (NULL)");
  542.             $this->popErrorHandling();
  543.             if ($result === DB_OK) {
  544.                 $id = @sqlite_last_insert_rowid($this->connection);
  545.                 if ($id != 0) {
  546.                     return $id;
  547.                 }
  548.             } elseif ($ondemand && DB::isError($result) &&
  549.                       $result->getCode() == DB_ERROR_NOSUCHTABLE)
  550.             {
  551.                 $result = $this->createSequence($seq_name);
  552.                 if (DB::isError($result)) {
  553.                     return $this->raiseError($result);
  554.                 } else {
  555.                     $repeat = 1;
  556.                 }
  557.             }
  558.         } while ($repeat);
  559.  
  560.         return $this->raiseError($result);
  561.     }
  562.  
  563.     // }}}
  564.     // {{{ getDbFileStats()
  565.  
  566.     /**
  567.      * Get the file stats for the current database
  568.      *
  569.      * Possible arguments are dev, ino, mode, nlink, uid, gid, rdev, size,
  570.      * atime, mtime, ctime, blksize, blocks or a numeric key between
  571.      * 0 and 12.
  572.      *
  573.      * @param string $arg  the array key for stats()
  574.      *
  575.      * @return mixed  an array on an unspecified key, integer on a passed
  576.      *                arg and false at a stats error
  577.      */
  578.     function getDbFileStats($arg = '')
  579.     {
  580.         $stats = stat($this->dsn['database']);
  581.         if ($stats == false) {
  582.             return false;
  583.         }
  584.         if (is_array($stats)) {
  585.             if (is_numeric($arg)) {
  586.                 if (((int)$arg <= 12) & ((int)$arg >= 0)) {
  587.                     return false;
  588.                 }
  589.                 return $stats[$arg ];
  590.             }
  591.             if (array_key_exists(trim($arg), $stats)) {
  592.                 return $stats[$arg ];
  593.             }
  594.         }
  595.         return $stats;
  596.     }
  597.  
  598.     // }}}
  599.     // {{{ escapeSimple()
  600.  
  601.     /**
  602.      * Escapes a string according to the current DBMS's standards
  603.      *
  604.      * In SQLite, this makes things safe for inserts/updates, but may
  605.      * cause problems when performing text comparisons against columns
  606.      * containing binary data. See the
  607.      * {@link http://php.net/sqlite_escape_string PHP manual} for more info.
  608.      *
  609.      * @param string $str  the string to be escaped
  610.      *
  611.      * @return string  the escaped string
  612.      *
  613.      * @since Method available since Release 1.6.1
  614.      * @see DB_common::escapeSimple()
  615.      */
  616.     function escapeSimple($str)
  617.     {
  618.         return @sqlite_escape_string($str);
  619.     }
  620.  
  621.     // }}}
  622.     // {{{ modifyLimitQuery()
  623.  
  624.     /**
  625.      * Adds LIMIT clauses to a query string according to current DBMS standards
  626.      *
  627.      * @param string $query   the query to modify
  628.      * @param int    $from    the row to start to fetching (0 = the first row)
  629.      * @param int    $count   the numbers of rows to fetch
  630.      * @param mixed  $params  array, string or numeric data to be used in
  631.      *                         execution of the statement.  Quantity of items
  632.      *                         passed must match quantity of placeholders in
  633.      *                         query:  meaning 1 placeholder for non-array
  634.      *                         parameters or 1 placeholder per array element.
  635.      *
  636.      * @return string  the query string with LIMIT clauses added
  637.      *
  638.      * @access protected
  639.      */
  640.     function modifyLimitQuery($query, $from, $count, $params = array())
  641.     {
  642.         return "$query LIMIT $count OFFSET $from";
  643.     }
  644.  
  645.     // }}}
  646.     // {{{ modifyQuery()
  647.  
  648.     /**
  649.      * Changes a query string for various DBMS specific reasons
  650.      *
  651.      * This little hack lets you know how many rows were deleted
  652.      * when running a "DELETE FROM table" query.  Only implemented
  653.      * if the DB_PORTABILITY_DELETE_COUNT portability option is on.
  654.      *
  655.      * @param string $query  the query string to modify
  656.      *
  657.      * @return string  the modified query string
  658.      *
  659.      * @access protected
  660.      * @see DB_common::setOption()
  661.      */
  662.     function modifyQuery($query)
  663.     {
  664.         if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) {
  665.             if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
  666.                 $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
  667.                                       'DELETE FROM \1 WHERE 1=1', $query);
  668.             }
  669.         }
  670.         return $query;
  671.     }
  672.  
  673.     // }}}
  674.     // {{{ sqliteRaiseError()
  675.  
  676.     /**
  677.      * Produces a DB_Error object regarding the current problem
  678.      *
  679.      * @param int $errno  if the error is being manually raised pass a
  680.      *                     DB_ERROR* constant here.  If this isn't passed
  681.      *                     the error information gathered from the DBMS.
  682.      *
  683.      * @return object  the DB_Error object
  684.      *
  685.      * @see DB_common::raiseError(),
  686.      *      DB_sqlite::errorNative(), DB_sqlite::errorCode()
  687.      */
  688.     function sqliteRaiseError($errno = null)
  689.     {
  690.         $native = $this->errorNative();
  691.         if ($errno === null) {
  692.             $errno = $this->errorCode($native);
  693.         }
  694.  
  695.         $errorcode = @sqlite_last_error($this->connection);
  696.         $userinfo = "$errorcode ** $this->last_query";
  697.  
  698.         return $this->raiseError($errno, null, null, $userinfo, $native);
  699.     }
  700.  
  701.     // }}}
  702.     // {{{ errorNative()
  703.  
  704.     /**
  705.      * Gets the DBMS' native error message produced by the last query
  706.      *
  707.      * {@internal This is used to retrieve more meaningfull error messages
  708.      * because sqlite_last_error() does not provide adequate info.}}
  709.      *
  710.      * @return string  the DBMS' error message
  711.      */
  712.     function errorNative()
  713.     {
  714.         return $this->_lasterror;
  715.     }
  716.  
  717.     // }}}
  718.     // {{{ errorCode()
  719.  
  720.     /**
  721.      * Determines PEAR::DB error code from the database's text error message
  722.      *
  723.      * @param string $errormsg  the error message returned from the database
  724.      *
  725.      * @return integer  the DB error number
  726.      */
  727.     function errorCode($errormsg)
  728.     {
  729.         static $error_regexps;
  730.         if (!isset($error_regexps)) {
  731.             $error_regexps = array(
  732.                 '/^no such table:/' => DB_ERROR_NOSUCHTABLE,
  733.                 '/^no such index:/' => DB_ERROR_NOT_FOUND,
  734.                 '/^(table|index) .* already exists$/' => DB_ERROR_ALREADY_EXISTS,
  735.                 '/PRIMARY KEY must be unique/i' => DB_ERROR_CONSTRAINT,
  736.                 '/is not unique/' => DB_ERROR_CONSTRAINT,
  737.                 '/columns .* are not unique/i' => DB_ERROR_CONSTRAINT,
  738.                 '/uniqueness constraint failed/' => DB_ERROR_CONSTRAINT,
  739.                 '/may not be NULL/' => DB_ERROR_CONSTRAINT_NOT_NULL,
  740.                 '/^no such column:/' => DB_ERROR_NOSUCHFIELD,
  741.                 '/column not present in both tables/i' => DB_ERROR_NOSUCHFIELD,
  742.                 '/^near ".*": syntax error$/' => DB_ERROR_SYNTAX,
  743.                 '/[0-9]+ values for [0-9]+ columns/i' => DB_ERROR_VALUE_COUNT_ON_ROW,
  744.             );
  745.         }
  746.         foreach ($error_regexps as $regexp => $code) {
  747.             if (preg_match($regexp, $errormsg)) {
  748.                 return $code;
  749.             }
  750.         }
  751.         // Fall back to DB_ERROR if there was no mapping.
  752.         return DB_ERROR;
  753.     }
  754.  
  755.     // }}}
  756.     // {{{ tableInfo()
  757.  
  758.     /**
  759.      * Returns information about a table
  760.      *
  761.      * @param string         $result  a string containing the name of a table
  762.      * @param int            $mode    a valid tableInfo mode
  763.      *
  764.      * @return array  an associative array with the information requested.
  765.      *                 A DB_Error object on failure.
  766.      *
  767.      * @see DB_common::tableInfo()
  768.      * @since Method available since Release 1.7.0
  769.      */
  770.     function tableInfo($result, $mode = null)
  771.     {
  772.         if (is_string($result)) {
  773.             /*
  774.              * Probably received a table name.
  775.              * Create a result resource identifier.
  776.              */
  777.             $id = @sqlite_array_query($this->connection,
  778.                                       "PRAGMA table_info('$result');",
  779.                                       SQLITE_ASSOC);
  780.             $got_string = true;
  781.         } else {
  782.             $this->last_query = '';
  783.             return $this->raiseError(DB_ERROR_NOT_CAPABLE, null, null, null,
  784.                                      'This DBMS can not obtain tableInfo' .
  785.                                      ' from result sets');
  786.         }
  787.  
  788.         if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  789.             $case_func = 'strtolower';
  790.         } else {
  791.             $case_func = 'strval';
  792.         }
  793.  
  794.         $count = count($id);
  795.         $res   = array();
  796.  
  797.         if ($mode) {
  798.             $res['num_fields'] = $count;
  799.         }
  800.  
  801.         for ($i = 0; $i < $count; $i++) {
  802.             if (strpos($id[$i]['type'], '(') !== false) {
  803.                 $bits = explode('(', $id[$i]['type']);
  804.                 $type = $bits[0];
  805.                 $len  = rtrim($bits[1],')');
  806.             } else {
  807.                 $type = $id[$i]['type'];
  808.                 $len  = 0;
  809.             }
  810.  
  811.             $flags = '';
  812.             if ($id[$i]['pk']) {
  813.                 $flags .= 'primary_key ';
  814.             }
  815.             if ($id[$i]['notnull']) {
  816.                 $flags .= 'not_null ';
  817.             }
  818.             if ($id[$i]['dflt_value'] !== null) {
  819.                 $flags .= 'default_' . rawurlencode($id[$i]['dflt_value']);
  820.             }
  821.             $flags = trim($flags);
  822.  
  823.             $res[$i] = array(
  824.                 'table' => $case_func($result),
  825.                 'name'  => $case_func($id[$i]['name']),
  826.                 'type'  => $type,
  827.                 'len'   => $len,
  828.                 'flags' => $flags,
  829.             );
  830.  
  831.             if ($mode & DB_TABLEINFO_ORDER) {
  832.                 $res['order'][$res[$i]['name']] = $i;
  833.             }
  834.             if ($mode & DB_TABLEINFO_ORDERTABLE) {
  835.                 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  836.             }
  837.         }
  838.  
  839.         return $res;
  840.     }
  841.  
  842.     // }}}
  843.     // {{{ getSpecialQuery()
  844.  
  845.     /**
  846.      * Obtains the query string needed for listing a given type of objects
  847.      *
  848.      * @param string $type  the kind of objects you want to retrieve
  849.      * @param array  $args  SQLITE DRIVER ONLY: a private array of arguments
  850.      *                       used by the getSpecialQuery().  Do not use
  851.      *                       this directly.
  852.      *
  853.      * @return string  the SQL query string or null if the driver doesn't
  854.      *                  support the object type requested
  855.      *
  856.      * @access protected
  857.      * @see DB_common::getListOf()
  858.      */
  859.     function getSpecialQuery($type, $args = array())
  860.     {
  861.         if (!is_array($args)) {
  862.             return $this->raiseError('no key specified', null, null, null,
  863.                                      'Argument has to be an array.');
  864.         }
  865.  
  866.         switch ($type) {
  867.             case 'master':
  868.                 return 'SELECT * FROM sqlite_master;';
  869.             case 'tables':
  870.                 return "SELECT name FROM sqlite_master WHERE type='table' "
  871.                        . 'UNION ALL SELECT name FROM sqlite_temp_master '
  872.                        . "WHERE type='table' ORDER BY name;";
  873.             case 'schema':
  874.                 return 'SELECT sql FROM (SELECT * FROM sqlite_master '
  875.                        . 'UNION ALL SELECT * FROM sqlite_temp_master) '
  876.                        . "WHERE type!='meta' "
  877.                        . 'ORDER BY tbl_name, type DESC, name;';
  878.             case 'schemax':
  879.             case 'schema_x':
  880.                 /*
  881.                  * Use like:
  882.                  * $res = $db->query($db->getSpecialQuery('schema_x',
  883.                  *                   array('table' => 'table3')));
  884.                  */
  885.                 return 'SELECT sql FROM (SELECT * FROM sqlite_master '
  886.                        . 'UNION ALL SELECT * FROM sqlite_temp_master) '
  887.                        . "WHERE tbl_name LIKE '{$args['table']}' "
  888.                        . "AND type!='meta' "
  889.                        . 'ORDER BY type DESC, name;';
  890.             case 'alter':
  891.                 /*
  892.                  * SQLite does not support ALTER TABLE; this is a helper query
  893.                  * to handle this. 'table' represents the table name, 'rows'
  894.                  * the news rows to create, 'save' the row(s) to keep _with_
  895.                  * the data.
  896.                  *
  897.                  * Use like:
  898.                  * $args = array(
  899.                  *     'table' => $table,
  900.                  *     'rows'  => "id INTEGER PRIMARY KEY, firstname TEXT, surname TEXT, datetime TEXT",
  901.                  *     'save'  => "NULL, titel, content, datetime"
  902.                  * );
  903.                  * $res = $db->query( $db->getSpecialQuery('alter', $args));
  904.                  */
  905.                 $rows = strtr($args['rows'], $this->keywords);
  906.  
  907.                 $q = array(
  908.                     'BEGIN TRANSACTION',
  909.                     "CREATE TEMPORARY TABLE {$args['table']}_backup ({$args['rows']})",
  910.                     "INSERT INTO {$args['table']}_backup SELECT {$args['save']} FROM {$args['table']}",
  911.                     "DROP TABLE {$args['table']}",
  912.                     "CREATE TABLE {$args['table']} ({$args['rows']})",
  913.                     "INSERT INTO {$args['table']} SELECT {$rows} FROM {$args['table']}_backup",
  914.                     "DROP TABLE {$args['table']}_backup",
  915.                     'COMMIT',
  916.                 );
  917.  
  918.                 /*
  919.                  * This is a dirty hack, since the above query will not get
  920.                  * executed with a single query call so here the query method
  921.                  * will be called directly and return a select instead.
  922.                  */
  923.                 foreach ($q as $query) {
  924.                     $this->query($query);
  925.                 }
  926.                 return "SELECT * FROM {$args['table']};";
  927.             default:
  928.                 return null;
  929.         }
  930.     }
  931.  
  932.     // }}}
  933. }
  934.  
  935. /*
  936.  * Local variables:
  937.  * tab-width: 4
  938.  * c-basic-offset: 4
  939.  * End:
  940.  */
  941.  
  942. ?>
  943.